
import { BrowserRouter as Router, Route, Link, Switch, useHistory, useLocation } from "react-router-dom";
import { useContext, createContext, useState } from "react";
const routes = [
    {
        path: "/public",
        name: "Public",
        component: Public
    },
    {
        path: "/protected",
        name: "Protected",
        component: Protected
    },
    {
        path: "/login",
        name: "Login",
        component: Login
    }
];
export default function AuthExample() {
    return (
        <ProvideAuth>
            <Router>
                <div>
                    <AuthButton />
                    <ul>
                        {
                            routes.map((route, i) => {
                                if (route.name !== "login") {
                                    return (
                                        <li key={i}>
                                            <Link to={route.path}>{route.name}</Link>
                                        </li>
                                    )
                                }else{
                                    return null;
                                }
                            })
                        }
                    </ul>
                </div>

                <Switch>
                    {
                        routes.map((route, i) => {
                            return (
                                <Route key={i} path={route.path}  exact={i === 0 ? true : false}>
                                    <route.component></route.component>
                                </Route>
                            )
                        })
                    }
                </Switch>
            </Router>
        </ProvideAuth>
    )
}

// 这里边 context 的作用是什么？—— 在登陆组件内部登陆后，设置了 user 的值，这个设置的值需要在和 Login 没有层级关系的组件 AuthButton 中用到
// 这个 Provider 和 Consumer 不要太鸡肋——不不不，不鸡肋，可以通过 Comsumer 使用共享数据，也可以通过 useContext(context) 直接获取共享数据
// state 其实就是设置了一个


//没有 defaultValue 的 context
var authContext = createContext();

const fakeAuth = {
    isAuthenticated: false,
    signIn(cb) {
        fakeAuth.isAuthenticated = true;
        setTimeout(cb, 1000);
    },
    signOut(cb) {
        fakeAuth.isAuthenticated = false;
        setTimeout(cb, 1000);
    }
};

function Public() {
    return <h3>Public</h3>;
}

function Protected() {
    return <h3>Protected</h3>;
}

//登陆成功会替换当前登录页，难道不应该是回退吗？
function Login() {
    let history = useHistory();
    let location = useLocation();
    //使用共享的数据
    let auth = useAuth();
    let { from } = location.state || { from: { pathname: "/" } };
    let login = () => {
        auth.signin(() => {
            history.replace(from);
        });
    }
    return (
        <div>
            <p>You must log in to view the page at {from.pathname}</p>
            <button onClick={login}>Log in</button>
        </div>
    );
}

//展示退出按钮
function AuthButton() {
    let history = useHistory();
    console.log("history:");
    console.log(history);
    //获取 auth 对象，获取共享的 context 数据
    let auth = useAuth();
    return auth.user ? (
        <p>
            
            Welcome! {auth.user}
            <button onClick={e => {
                auth.signout(() => {
                    history.push("/");
                });
            }}>Log Out</button>
        </p>
    ) : (<p>You are not logged in.</p>)
}

//用于在组件之间共享
function useAuth() {
    return useContext(authContext);
}

//为什么这里要把 user、登陆、退出 写出来?
//登陆之后和退出之后，需要重置用户数据
//user 的值变化只能通过 sigin 和 sigout
function useProvideAuth() {
    let [user, setUser] = useState(null);
    let signin = cb => {
        return fakeAuth.signIn(() => {
            setUser("user");
            cb();
        });
    }
    let signout = cb => {
        return fakeAuth.signOut(() => {
            setUser(null);
            cb();
        });
    }
    return {
        user,
        signin,
        signout
    };
}

//最上层的权限控制
function ProvideAuth({children}) {
    var auth = useProvideAuth();
    return (
        <authContext.Provider value={auth}>
            {children}
        </authContext.Provider>
    )
}